"""Checks indentation of all files in a branch"""

import os
import re
import StringIO
import sys
import tabnanny
import tempfile

import term.framework

from svnhooks.precommit import PreCommitChecker


def main():
    """Call application object"""
    Application().main(sys.argv)


class Application(PreCommitChecker):

    def check_file(self, filename, file_lines):
        self.check_whitespace(filename, file_lines)
        self.check_via_tabnanny(filename, file_lines)
#        self.ensure_no_cr_lf(file_lines)

    def check_whitespace(self, filename, lines):
        for (i, line) in enumerate(lines):
            for (ptrn, msg) in self.conditions:
                if ptrn.search(line):
                    self.error_recorder.add(filename, msg % (i+1))

    conditions = [(re.compile(r'^\s*\t'), "Indentation Error: leading tabs (line %i)"),
                  (re.compile(r'\r\n$'), "Line Ending Error: \\r\\n instead of \\n (line %i)"),
                  (re.compile(r'\\\s+\n$'), "Line Ending Error: broken continuation (line %i)"),
                  ]

    def check_via_tabnanny(self, filename, file_lines):
        tempfile = self.write_temp_file(file_lines)
        try:
            err = self.captured_stderr(tabnanny.check, tempfile)
            if err:
                err = re.sub(r"^'.+': ", "", err)
                self.error_recorder.add(filename, err)
        finally:
            os.unlink(tempfile)

    def write_temp_file(self, contents):
        (fd, filename) = tempfile.mkstemp()
        os.close(fd)
        self.write_file(filename, contents)

    def write_file(self, filename, contents):
        f = file(filename, 'w')
        try:
            for line in contents:
                f.write(line)
            return filename
        finally:
            f.close()

    def captured_stderr(self, func, *pargs, **vargs):
        saved_stderr = sys.stderr
        sys.stderr = StringIO.StringIO()
        try:
            func(*pargs, **vargs)
            return sys.stderr.getvalue()
        finally:
            sys.stderr = saved_stderr

